﻿//using System;
//using System.Collections.Generic;
//using System.Collections.ObjectModel;
//using System.IO;
//using System.Linq;
//using System.Reflection;
//using System.Threading;
//using System.Threading.Tasks;
//using Client_Server_Interface;

//namespace BTM_Client_Application.SupportClasses
//{
//    public class DeviceWorker : IMonitoringDeviceWorker, IDisposable
//    {
//        //private List<DeviceTreeItem.DeviceInfo> _devList;
//        private static event NewErrorRecordDelegate NewErrorRecordEvent;
//        private bool _initialized;
//        private bool _started;
//        private static int _statusRequestPeriod;
//        private CancellationTokenSource _cts;
//        private CancellationToken _ct;
//        private TaskFactory _tf;
//        private Task[] _tasks;

//        protected static void OnNewErrorRecordEvent(DeviceTreeItem.DeviceInfo device, ObservableCollection<ErrorListRecord> records, int unreadCount, int totalUnreadCount)
//        {
//            NewErrorRecordDelegate handler = NewErrorRecordEvent;
//            if (handler != null) handler(device, records, unreadCount, totalUnreadCount);
//        }

//        //public static Dictionary<DeviceTreeItem.DeviceInfo, List<ErrorListRecord>> DevicesState { get; set; }
//        public List<IDeviceInterface> ActiveDeviceList { get; set; }

//        public static List<IDeviceInterface> CreateDeviceList(DeviceTree devTree)
//        {
//            var devList = (from region in devTree.DeviceTreeItems
//                           from station in region.SubItems
//                           from device in station.SubItems
//                           select device.AdditionalInfo as DeviceTreeItem.DeviceInfo).ToList();
//            //в _devList нет данных по регионам
//            var activeDeviceList = new List<IDeviceInterface>();
//            foreach (var deviceInfo in devList)
//            {
//                String devLibName = deviceInfo.LibraryName;
//                try
//                {

//                    devLibName = AliveInfo.DBwork.GetLibraryName(deviceInfo.Device);
//                }
//                catch (Exception)
//                {
//                    AliveInfo.DBwork.SetLibraryName(deviceInfo.Device, devLibName);
//                }
//                deviceInfo.LibraryName = devLibName;
//                var hw = new HardWorker(devLibName);
//                try
//                {
//                    hw.Initialize(deviceInfo.IpAddress);
//                    if (deviceInfo.IsActive)
//                        activeDeviceList.Add(new Device(hw.GetStatus, deviceInfo, OnNewErrorRecordEvent));
//                }
//                catch (ClientException ex)
//                {
//                    if (ex.Message != ClientExceptionMessage.FILE_IS_NOT_EXIST)
//                        throw;
//                }
//            }
//            return activeDeviceList;
//        }

//        public void Initialize(List<IDeviceInterface> activeDeviceList, NewErrorRecordDelegate newErrorRecordReaction, string requestPeriod)
//        {
//            if (_initialized)
//            {
//                return;
//            }

//            int statusRequestPeriod;
//            if (!int.TryParse(requestPeriod, out statusRequestPeriod))
//            {
//                IncorrectInputValueException.Throw("integer status request period", requestPeriod);
//            }
//            _statusRequestPeriod = statusRequestPeriod;
//            NewErrorRecordEvent = null;
//            NewErrorRecordEvent += newErrorRecordReaction;
//            _initialized = true;
//            ActiveDeviceList = activeDeviceList;
//        }

//        public void ChangeDeviceOpenedState(DeviceTreeItem.DeviceInfo deviceInfo, bool opened)
//        {
//            var dev = ActiveDeviceList.Single(d => d.GetHashCode() == deviceInfo.GetHashCode());
//            dev.Opened = opened;
//        }

//        public bool AllOpenedDevicesState
//        {
//            set
//            {
//                if (value)
//                {
//                    OnNewErrorRecordEvent(null, null, 0, 0);
//                    foreach (var deviceInterface in ActiveDeviceList)
//                    {
//                        deviceInterface.UnreadCount = 0;
//                    }
//                }
//                DeviceBlank.AllOpened = value;
//            }
//        }

//        public void Start()
//        {
//            if (!_initialized)
//                ClientException.Throw(ClientExceptionMessage.NOT_INITIALIZED);
//            if (_started)
//                ClientException.Throw(ClientExceptionMessage.ALREADY_STARTED);
//            _cts = new CancellationTokenSource();
//            _ct = _cts.Token;
//            _tf = new TaskFactory();
//            _tasks = new Task[ActiveDeviceList.Count];
//            int i = 0;
//            foreach (var device in ActiveDeviceList)
//            {
//                var device1 = device;
//                _tasks[i++] = _tf.StartNew(() => device1.Action(_ct), _ct);
//            }
//            _started = true;
//        }

//        public void Stop()
//        {
//            if (!_started)
//                return;
//            _cts.Cancel();
//            try
//            {
//                Task.WaitAll(_tasks, 2000, _ct);
//            }
//            catch (OperationCanceledException)
//            {
//                DeviceBlank.TotalUnreadRecordsCount = 0;
//                OnNewErrorRecordEvent(null, null, 0, 0);
//                _started = false;
//                _initialized = false;
//            }
//        }

//        /// <summary>
//        /// Работает со всеми активными устройствами. Проводит опрос и заполняет списки с ошибками.
//        /// </summary>
//        public class Device : DeviceBlank
//        {

//            public Device(GetStatusDelegate getStatus, DeviceTreeItem.DeviceInfo deviceInfo, NewErrorRecordDelegate errorDelegate)
//            {
//                GetStatus = getStatus;
//                DevInfo = deviceInfo;
//                OnErrorAppear = errorDelegate;
//                UnreadCount = 0;
//                Opened = false;
//            }

//            /// <summary>
//            /// Вся работа по проверке статусов устройств.
//            /// </summary>
//            /// <param name="ct">Токен отмены.</param>
//            public override void Action(CancellationToken ct)
//            {
//                while (true)
//                {
//                    if (ct.IsCancellationRequested)
//                        break;
//                    var status = GetStatus();
//                    CreateErrorsList(status);
//                    OnErrorAppear(DevInfo, ErrorsList, UnreadCount, TotalUnreadRecordsCount);
//                    OnErrorsListChanged();
//                    Thread.Sleep(_statusRequestPeriod);
//                }
//            }

//            /// <summary>
//            /// Разбивает строку от устройства на список для заполнения datagrid.
//            /// </summary>
//            /// <param name="status">Строка с ошибками от устройтва.</param>
//            /// <returns></returns>
//            protected override void CreateErrorsList(string status)
//            {
//                int added = 0;
//                bool allAdded = ErrorsList == null || ErrorsList.Count < 1;
//                //Делим на ошибки
//                var records = status.Split(';');
//                if (!records.Any())
//                    ErrorsList = new ObservableCollection<ErrorListRecord>();
//                var list = new ObservableCollection<ErrorListRecord>();
//                //Все записи с прошлого цикла помечаются как старые
//                if (ErrorsList != null)
//                    foreach (var errorListRecord in ErrorsList)
//                    {
//                        if (errorListRecord.State != ErrorListRecord.RecordState.Delete)
//                            errorListRecord.State = ErrorListRecord.RecordState.Old;
//                    }
//                //Перебор всех записей, полученных с устройства
//                foreach (var record in records)
//                {
//                    if (record == "")
//                        continue;
//                    if (record == "ok")
//                    {
//                        break;
//                    }
//                    //Если ok то сплитить нечего!!!!!!!!
//                    var split = record.Split(':');
//                    var severity = split[0];        //Приоритет (info, warning, alarm, err)
//                    var info = split[1];
//                    var newError = new ErrorListRecord
//                    {
//                        Date = DateTime.Now,
//                        Device = DevInfo.Device,
//                        Info = info,
//                        Region = DevInfo.Region,
//                        Station = DevInfo.ParentInfo.Station,
//                        Status = severity
//                    };
//                    if (allAdded)
//                    {
//                        newError.State = ErrorListRecord.RecordState.Add;
//                        added++;
//                    }
//                    else
//                    {
//                        IEnumerable<ErrorListRecord> t = ErrorsList.Where(e => e.GetRecordId() == newError.GetRecordId()).ToList();
//                        //Если такой же записи нет, то текущая добавляется
//                        if (!t.Any())
//                        {
//                            newError.State = ErrorListRecord.RecordState.Add;
//                            added++;
//                        }
//                        else
//                        {
//                            ErrorListRecord prevDev = t.Single();
//                            //Если запись есть, но на прошлом цикле была удалена, то добавляется снова
//                            if (prevDev.State == ErrorListRecord.RecordState.Delete)
//                            {
//                                newError.State = ErrorListRecord.RecordState.Add;
//                                added++;
//                            }
//                            //Если такая же запись есть, то ничего не происходит
//                            else
//                            {
//                                prevDev.State = ErrorListRecord.RecordState.Seen;
//                                newError = prevDev;
//                            }
//                        }
//                    }
//                    //Запись добавляется в обновленный список
//                    list.Add(newError);
//                }
//                if (!allAdded)
//                    //Среди записей, оставшихся с прошлого цикла ищутся те, которые нужно удалить из списка и помечаются
//                    foreach (var error in ErrorsList)
//                    {
//                        if (error.State != ErrorListRecord.RecordState.Seen && error.State != ErrorListRecord.RecordState.Delete)
//                        {
//                            error.State = ErrorListRecord.RecordState.Delete;
//                            list.Add(error);
//                            if (UnreadCount > 0)
//                                added--;
//                        }
//                    }
//                //Старый список заменяется обновленным
//                ErrorsList = list;
//                if (AllOpened)
//                    TotalUnreadRecordsCount = 0;
//                else if (!Opened)
//                {
//                    TotalUnreadRecordsCount -= UnreadCount;
//                    UnreadCount += added;
//                    TotalUnreadRecordsCount += UnreadCount;
//                }
//            }
//        }

//        /// <summary>
//        /// Используется для работы с библиотеками для каждого устройства.
//        /// </summary>
//        private class HardWorker
//        {
//            private bool _initialized;
//            private DynamicFunc _dynamicFunc;
//            //private readonly string _dllName;
//            private readonly string _dllPath;
//            private const string LibsPath = "\\Libs\\";
//            private string _devIp;

//            public HardWorker(string libName)
//            {
//                //_dllName = libName;
//                _dllPath = AliveInfo.CurDir + LibsPath + libName;
//            }

//            /// <summary>
//            /// Получение строки состояни, списка текущих ошибок на устройстве.
//            /// </summary>
//            /// <returns></returns>
//            public string GetStatus()
//            {
//                if (!_initialized)
//                {
//                    ClientException.Throw(ClientExceptionMessage.NOT_INITIALIZED);
//                }

//                string[] parsString = { _devIp };
//                var args = new object[2];
//                args[0] = "getstatus";
//                args[1] = parsString;
//                return _dynamicFunc(args);
//            }

//            public void Initialize(string ipAddress)
//            {
//                if (_initialized)
//                    return;
//                if (!File.Exists(_dllPath))
//                {
//                    ClientException.Throw(ClientExceptionMessage.FILE_IS_NOT_EXIST);
//                }
//                if (!Res.CheckIp(ipAddress))
//                {
//                    IncorrectInputValueException.Throw(ClientExceptionMessage.INCORRECT_IP_ADDRESS, ipAddress);
//                }
//                _devIp = ipAddress;
//                Assembly assemblyDll = Assembly.LoadFile(_dllPath);
//                Type[] typeslist = assemblyDll.GetExportedTypes();
//                MethodInfo[] methods = typeslist[0].GetMethods();
//                var callMethod = methods.First(met => met.Name.Contains("CallMethod"));
//                var callClass = Activator.CreateInstance(typeslist[0]);
//                _dynamicFunc = MakeDynamicFunc(callClass, callMethod);
//                _initialized = true;
//            }

//            private delegate string DynamicFunc(params object[] parameters);

//            private static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
//            {
//                return par => (string)method.Invoke(target, par);
//            }
//        }

//        public void Dispose()
//        {
//            Stop();
//        }
//    }
//}
